package com.adobe
{
	import flash.utils.Dictionary;
	import flash.utils.describeType;
	import flash.utils.getDefinitionByName;
	import flash.utils.getQualifiedClassName;
	
	public class Reflection
	{
		public function Reflection()
		{
		}
		
		[ArrayElementType(type='String')]
		public static function functionNames(o:Object):Array {
			var result:Array = new Array();
			
			var type:XML = describeType(o);
			
			var methods:XMLList = type.method;
			for each (var method:XML in methods) {
				result.push(method.@name.toXMLString());
			}
			
			return result;
		}
		
		[ArrayElementType(type='String')]
		public static function functionNamesWithMetadata(o:Object, tagName:String):Array {
			var result:Array = new Array();
			
			var type:XML = describeType(o);
			var methods:XMLList = type.method;

			for each (var method:XML in methods) {
				var metadata:XMLList = method.metadata.(@name==tagName); 
				if (metadata.length() > 0) {
					result.push(method.@name.toXMLString());
				}
			}
			
			return result;
		}
		
		[ArrayElementType(type='Function')]
		public static function functions(o:Object):Array {
			var result:Array = new Array();
						
			var type:XML = describeType(o);
			
			var methods:XMLList = type.method;
			for each (var method:XML in methods) {
				var m:Function = o[method.@name.toXMLString()];
				result.push(m);
			}
			
			return result;
		}
		
		[ArrayElementType(type='Function')]
		public static function functionsWithMetadata(o:Object, tagName:String):Array {
			var result:Array = new Array();
			
			var type:XML = describeType(o);
			var methods:XMLList = type.method;

			for each (var method:XML in methods) {
				var metadata:XMLList = method.metadata.(@name==tagName); 
				if (metadata.length() > 0) {
					var m:Function = o[method.@name.toXMLString()];
					result.push(m);
				}
			}
			
			return result;
		}
		
		[ArrayElementType(type='XML')]
		public static function metadataFor(o:Object, functionName:String, tagName:String):XMLList {
			var result:XMLList = null;
			
			var type:XML = describeType(o);
			var methods:XMLList = type.method.(@name == functionName);
			if (methods.length() > 0) {
				result = methods[0].elements('metadata');
			}
			
			return result;
		}
		
		public static function mapFunctionsWithMetadata(o:Object, metadataName:String, attributeName:String):Dictionary {
			var result:Dictionary = new Dictionary();
						
			var type:XML = describeType(o);
			var methods:XMLList = type.method;
			
			for each (var method:XML in methods) {
				var metadata:XMLList = method.metadata.(@name==metadataName);
				for each (var tag:XML in metadata) {
					var args:XMLList = tag.arg.(@key == attributeName);
					
					for each (var arg:XML in args) {
						result[arg.@value.toXMLString()] = o[method.@name.toXMLString()];
					}					
				}
				 
			}
			
			return result;
		}
		
		public static function getClass(obj:Object):Class {
   			return Class(getDefinitionByName(getQualifiedClassName(obj)));
		}

	}
}